﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Ruminate.GUI.Framework;
using Microsoft.Xna.Framework;
using Ruminate.GUI.Content;
using fess.RPG;

namespace fess.Screens
{
  static class UIResources
  {
    public static Texture2D BlueLine, RedLine;
  }

  interface IUIActive : IActive
  {
    Widget Widget { get; }
  }

  interface IScreen
  {
    void Draw(GameTime gameTime);
    bool Update(GameTime gameTime);
  }

  class CharPic : IUIActive
  {
    ActionCharacter character;
    Panel panel;
    Image health, mana;
    Label header;

    public CharPic(ActionCharacter character)
    {
      this.character = character;

      panel = new Panel(0, 0, 200, 56);
      panel.AddWidget(new Image(0, 0, 48, 48, character.FacePic));
      panel.AddWidget(header = new Label(60, 0, string.Format("{0} [{1}]", character.Name, character.Level)));
      panel.AddWidget(health = new Image(60, 16, 128, 16, UIResources.RedLine));
      panel.AddWidget(new Label(90, 16, "Здоровье"));
      panel.AddWidget(mana = new Image(60, 32, 128, 16, UIResources.BlueLine));
      panel.AddWidget(new Label(90, 32, "Сила духа"));
    }

    public bool Update(TimeSpan time)
    {
      if (character.Dead)
        return false;

      var area = health.Area;
      area.Width = character.MaxHealth == 0 ? 0 : (int)(128 * character.Health / character.MaxHealth);
      health.Area = area;
      health.Layout();

      area = mana.Area;
      area.Width = character.MaxMana == 0 ? 0 : (int)(128 * character.Mana / character.MaxMana);
      mana.Area = area;
      mana.Layout();

      header.Value = string.Format("{0} [{1}]", character.Name, character.Level);

      return true;
    }

    public Widget Widget { get { return panel; } }

    public ActionCharacter Character { get { return character; } }
  }

  class MessageWindow : IUIActive
  {
    ActionCharacter character;
    Panel panel;
    TimeSpan appear;
    protected TimeSpan duration;

    public Widget Widget { get { return panel; } }

    public MessageWindow(ActionCharacter speaker, string message, TimeSpan appear, double duration = 10)
    {
      this.character = speaker;
      this.duration = TimeSpan.FromSeconds(duration);
      this.appear = appear;
      panel = new Panel(0, 0, 400, 80);

      panel.AddWidget(new Image(0, 0, 72, 72, character.FacePic));
      panel.AddWidget(new Label(85, 0, speaker.Name + ":"));
      panel.AddWidget(new Label(90, 16, "\"" + message + "\""));
      panel.Visible = false;
    }

    public MessageWindow(ActionCharacter speaker, string message, TimeSpan appear, Texture2D picture, double duration = 10)
    {
      this.character = speaker;
      this.duration = TimeSpan.FromSeconds(duration);
      this.appear = appear;
      panel = new Panel(0, 0, 400, 98);

      panel.AddWidget(new Image(0, 0, 90, 90, picture));
      panel.AddWidget(new Label(85 + 18, 0, speaker.Name + ":"));
      panel.AddWidget(new Label(90 + 18, 16, "\"" + message + "\""));
      panel.Visible = false;
    }

    public bool Update(TimeSpan time)
    {
      if (character.Dead)
        return false;

      panel.Visible = time > appear;
      return time <= appear + duration;
    }
  }

  class AnswerWindow : MessageWindow
  {
    public AnswerWindow(ActionCharacter speaker, string message, TimeSpan appear, params Answer[] answers)
      : base(speaker, message, appear, 100000)
    {
      int x = 90;
      foreach (var answer in answers)
      {
        var answ = answer;
        var ans = new Button(x, 41, 100, answer.text, w => { duration = TimeSpan.Zero; speaker.Map.game.SkipMessage(); answ.action(); });
        x += 100;
        Widget.AddWidget(ans);
        ans.Width = 10;
      }
    }
  }

  class StackPanel : IActive
  {
    public List<IUIActive> children = new List<IUIActive>();
    Gui gui;
    Rectangle extents;
    bool reverse;

    public StackPanel(Rectangle extents, Gui gui, bool reverse = false)
    {
      this.extents = extents;
      this.gui = gui;
      this.reverse = reverse;
    }

    public void Add(IUIActive child, bool inFront = false)
    {
      if (inFront)
        children.Insert(0, child);
      else
        children.Add(child);

      gui.AddWidget(child.Widget);
      UpdateLayout();
    }

    private void UpdateLayout()
    {
      int loc = reverse ? extents.Bottom : extents.Top;
      bool cut = false;
      foreach (var cp in children)
      {
        gui.RemoveWidget(cp.Widget);

        if (cp.Widget.Visible)
        {
          if (cut)
            continue;

          var area = cp.Widget.Area;
          area.Location = new Point(extents.X, reverse ? loc - area.Height : loc);

          if (!extents.Contains(area))
          {
            cut = true;
            continue;
          }

          gui.AddWidget(cp.Widget);
          loc += area.Height * (reverse ? -1 : 1);
          cp.Widget.Area = area;
          cp.Widget.AbsoluteArea = area;
          cp.Widget.Layout();
        }
      }
    }

    public bool Update(TimeSpan time)
    {
      bool updated = false;
      for (int i = 0; i < children.Count; ++i)
      {
        bool wasVisible = children[i].Widget.Visible;
        if (!children[i].Update(time))
        {
          updated = true;
          gui.RemoveWidget(children[i].Widget);

          children.RemoveAt(i);
          --i;
        }
        else
          updated |= wasVisible != children[i].Widget.Visible;
      }

      if (updated)
        UpdateLayout();

      return true;
    }

    public void DropAll()
    {
      foreach (var cp in children)
        gui.RemoveWidget(cp.Widget);

      children.Clear();
    }

    public void Pop()
    {
      if (children.Count > 0)
      {
        gui.RemoveWidget(children[0].Widget);
        children.RemoveAt(0);
      }
    }

    public void RemoveAt(int i)
    {
      gui.RemoveWidget(children[i].Widget);
      children.RemoveAt(i);
      UpdateLayout();
    }

    public int Count { get { return children.Count; } }
  }

  class Timed : IActive
  {
    TimeSpan when;
    Action what;

    public Timed(TimeSpan when, Action what)
    {
      this.what = what;
      this.when = when;
    }

    public bool Update(TimeSpan time)
    {
      if (time < when)
        return true;

      what();
      return false;
    }
  }

  static class UIExts
  {
    public static void SetHeight(this Widget w, int height)
    {
      var area = w.Area;
      area.Height = height;
      w.Area = area;
      w.AbsoluteArea = area;
    }

    public static void SetWidth(this Widget w, int width)
    {
      var area = w.Area;
      area.Width = width;
      w.Area = area;
      w.AbsoluteArea = area;
    }
  }
}
